/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstdint>

#include "native_node.h"
#include "native_type.h"
#include "node/node_model.h"

#include "base/error/error_code.h"
#include "base/utils/utils.h"
#include "core/interfaces/arkoala/arkoala_api.h"

#ifdef __cplusplus
extern "C" {
#endif

Keels_ArkUI_NodeAdapterHandle Keels_ArkUI_NodeAdapter_Create(void)
{
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, nullptr);
    auto* nodeAdapter = fullImpl->getNodeAdapterAPI()->create();
    return reinterpret_cast<Keels_ArkUI_NodeAdapterHandle>(nodeAdapter);
}

void Keels_ArkUI_NodeAdapter_Dispose(Keels_ArkUI_NodeAdapterHandle handle)
{
    CHECK_NULL_VOID(handle);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_VOID(fullImpl);
    fullImpl->getNodeAdapterAPI()->dispose(reinterpret_cast<ArkUINodeAdapterHandle>(handle));
}

int32_t Keels_ArkUI_NodeAdapter_SetTotalNodeCount(Keels_ArkUI_NodeAdapterHandle handle, uint32_t size)
{
    CHECK_NULL_RETURN(handle, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, Keels::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
    return fullImpl->getNodeAdapterAPI()->setTotalNodeCount(reinterpret_cast<ArkUINodeAdapterHandle>(handle), size);
}

uint32_t Keels_ArkUI_NodeAdapter_GetTotalNodeCount(Keels_ArkUI_NodeAdapterHandle handle)
{
    CHECK_NULL_RETURN(handle, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, Keels::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
    return fullImpl->getNodeAdapterAPI()->getTotalNodeCount(reinterpret_cast<ArkUINodeAdapterHandle>(handle));
}

typedef void (*InnerArkUINodeAdapterEvent)(ArkUINodeAdapterEvent* event);
int32_t Keels_ArkUI_NodeAdapter_RegisterEventReceiver(
    Keels_ArkUI_NodeAdapterHandle handle, void* userData, void (*receiver)(Keels_ArkUI_NodeAdapterEvent* event))
{
    CHECK_NULL_RETURN(handle, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, Keels::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
    return fullImpl->getNodeAdapterAPI()->registerEventReceiver(reinterpret_cast<ArkUINodeAdapterHandle>(handle),
        userData, reinterpret_cast<InnerArkUINodeAdapterEvent>(receiver));
}

void Keels_ArkUI_NodeAdapter_UnregisterEventReceiver(Keels_ArkUI_NodeAdapterHandle handle)
{
    CHECK_NULL_VOID(handle);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_VOID(fullImpl);
    fullImpl->getNodeAdapterAPI()->unregisterEventReceiver(reinterpret_cast<ArkUINodeAdapterHandle>(handle));
}

int32_t Keels_ArkUI_NodeAdapter_ReloadAllItems(Keels_ArkUI_NodeAdapterHandle handle)
{
    CHECK_NULL_RETURN(handle, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, Keels::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
    return fullImpl->getNodeAdapterAPI()->notifyItemReloaded(reinterpret_cast<ArkUINodeAdapterHandle>(handle));
}

int32_t Keels_ArkUI_NodeAdapter_ReloadItem(Keels_ArkUI_NodeAdapterHandle handle, uint32_t startPosition, uint32_t itemCount)
{
    CHECK_NULL_RETURN(handle, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, Keels::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
    return fullImpl->getNodeAdapterAPI()->notifyItemChanged(
        reinterpret_cast<ArkUINodeAdapterHandle>(handle), startPosition, itemCount);
}

int32_t Keels_ArkUI_NodeAdapter_RemoveItem(Keels_ArkUI_NodeAdapterHandle handle, uint32_t startPosition, uint32_t itemCount)
{
    CHECK_NULL_RETURN(handle, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, Keels::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
    return fullImpl->getNodeAdapterAPI()->notifyItemRemoved(
        reinterpret_cast<ArkUINodeAdapterHandle>(handle), startPosition, itemCount);
}

int32_t Keels_ArkUI_NodeAdapter_InsertItem(Keels_ArkUI_NodeAdapterHandle handle, uint32_t startPosition, uint32_t itemCount)
{
    CHECK_NULL_RETURN(handle, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, Keels::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
    return fullImpl->getNodeAdapterAPI()->notifyItemInserted(
        reinterpret_cast<ArkUINodeAdapterHandle>(handle), startPosition, itemCount);
}

int32_t Keels_ArkUI_NodeAdapter_MoveItem(Keels_ArkUI_NodeAdapterHandle handle, uint32_t from, uint32_t to)
{
    CHECK_NULL_RETURN(handle, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, Keels::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
    return fullImpl->getNodeAdapterAPI()->notifyItemMoved(reinterpret_cast<ArkUINodeAdapterHandle>(handle), from, to);
}

int32_t Keels_ArkUI_NodeAdapter_GetAllItems(Keels_ArkUI_NodeAdapterHandle handle, Keels_ArkUI_NodeHandle** items, uint32_t* size)
{
    CHECK_NULL_RETURN(handle, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, Keels::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
    ArkUINodeHandle* innerNodes = nullptr;
    uint32_t totalSize = 0;
    auto error = fullImpl->getNodeAdapterAPI()->getAllItem(
        reinterpret_cast<ArkUINodeAdapterHandle>(handle), &innerNodes, &totalSize);
    if (error != 0) {
        return error;
    }
    *size = totalSize;
    if (*size == 0) {
        return Keels::Ace::ERROR_CODE_NO_ERROR;
    }
    *items = new Keels_ArkUI_NodeHandle[*size] {};
    for (uint32_t i = 0; i < *size; i++) {
        (*items[i]) = reinterpret_cast<Keels_ArkUI_NodeHandle>(fullImpl->getExtendedAPI()->getAttachNodePtr(innerNodes[i]));
    }
    delete[] innerNodes;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

void* Keels_ArkUI_NodeAdapterEvent_GetUserData(Keels_ArkUI_NodeAdapterEvent* event)
{
    CHECK_NULL_RETURN(event, nullptr);
    auto* innerEvent = reinterpret_cast<ArkUINodeAdapterEvent*>(event);
    return reinterpret_cast<void*>(innerEvent->extraParam);
}

Keels_ArkUI_NodeAdapterEventType Keels_ArkUI_NodeAdapterEvent_GetType(Keels_ArkUI_NodeAdapterEvent* event)
{
    CHECK_NULL_RETURN(event, Keels_ArkUI_NodeAdapterEventType(-1));
    auto* innerEvent = reinterpret_cast<ArkUINodeAdapterEvent*>(event);
    return static_cast<Keels_ArkUI_NodeAdapterEventType>(innerEvent->type);
}

Keels_ArkUI_NodeHandle Keels_ArkUI_NodeAdapterEvent_GetRemovedNode(Keels_ArkUI_NodeAdapterEvent* event)
{
    CHECK_NULL_RETURN(event, nullptr);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, nullptr);
    auto* innerEvent = reinterpret_cast<ArkUINodeAdapterEvent*>(event);
    return reinterpret_cast<Keels_ArkUI_NodeHandle>(fullImpl->getExtendedAPI()->getAttachNodePtr(innerEvent->handle));
}

Keels_ArkUI_NodeHandle Keels_ArkUI_NodeAdapterEvent_GetHostNode(Keels_ArkUI_NodeAdapterEvent* event)
{
    CHECK_NULL_RETURN(event, nullptr);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, nullptr);
    auto* innerEvent = reinterpret_cast<ArkUINodeAdapterEvent*>(event);
    return reinterpret_cast<Keels_ArkUI_NodeHandle>(fullImpl->getExtendedAPI()->getAttachNodePtr(innerEvent->handle));
}

uint32_t Keels_ArkUI_NodeAdapterEvent_GetItemIndex(Keels_ArkUI_NodeAdapterEvent* event)
{
    CHECK_NULL_RETURN(event, 0);
    auto* innerEvent = reinterpret_cast<ArkUINodeAdapterEvent*>(event);
    return innerEvent->index;
}

int32_t Keels_ArkUI_NodeAdapterEvent_SetItem(Keels_ArkUI_NodeAdapterEvent* event, Keels_ArkUI_NodeHandle handle)
{
    CHECK_NULL_RETURN(event, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    CHECK_NULL_RETURN(handle, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    auto* innerEvent = reinterpret_cast<ArkUINodeAdapterEvent*>(event);
    innerEvent->handle = handle->uiNodeHandle;
    innerEvent->nodeSet = true;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_NodeAdapterEvent_SetNodeId(Keels_ArkUI_NodeAdapterEvent* event, int32_t id)
{
    CHECK_NULL_RETURN(event, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    auto* innerEvent = reinterpret_cast<ArkUINodeAdapterEvent*>(event);
    innerEvent->id = id;
    innerEvent->idSet = true;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

Keels_ArkUI_ContextHandle Keels_ArkUI_GetContextByNode(Keels_ArkUI_NodeHandle node)
{
    CHECK_NULL_RETURN(node, nullptr);
    auto* fullImpl = Keels::Ace::NodeModel::GetFullImpl();
    CHECK_NULL_RETURN(fullImpl, nullptr);
    auto basicAPI = fullImpl->getBasicAPI();
    CHECK_NULL_RETURN(basicAPI, nullptr);
    int32_t instanceId = basicAPI->getContextByNode(node->uiNodeHandle);
    if (instanceId < 0) {
        return nullptr;
    }
    return new Keels_ArkUI_Context({ .id = instanceId });
}

#ifdef __cplusplus
};
#endif
